\section{Site LyonCapitale.fr}
L'application à porter sous Appcelerator Titanium est l'application "LYONCAPITALE NEWS",
disponible sur l'\gls{appstore}\cite{applyoncap}.
C'est un lecteur du site LyonCapitale.fr adapté au mobile. Le site LyonCapitale.fr utilise
le \gls{cms} Ez Publish depuis octobre 2009.


\subsection{Ez Publish}
Ez Publish est un \gls{cms} écrit en \gls{php}, sous licence GPL v2 (et aussi sous licence
propriétaire avec support commercial) qui incorpore un grand nombres
de fonctionnalités intéressantes pour un site de presse:
\begin{itemize}
\item Un éditeur de texte riche: permet une mise en page poussé sans connaissances de \gls{html},
simplement avec son navigateur web ;
\item \Glspl{workflow} de publication: on peut ainsi forcer la validation de chaque article par
un autre journaliste ou par le directeur de la rédaction ;
\item Gestion de version: on garde chaque version du contenu, avec les modifications apportées
ainsi que les auteurs de ces modifications ;
\item Gestion d'utilisateurs, de groupes et les rôles associés: cela permet d'avoir une gestion
précise et flexible des droits de chacun ;
\item Classes de contenu/d'objets définie par l'utilisateur: dans notre cas précis on a par exemple
la classe "lyoncapphotarticle" (un article standard avec photo), "lyoncapphotvideo" (un article
autour d'une video), ou encore "lyoncapdossier" (une collection d'article) ;
\item moteur modèles: pour chaque classe ( et type d'accès) on va pourvoir associer un
rendu différent, par exemple on va vouloir un modèle pour le site, une pour le site
mobile, et un autre pour donner les informations à l'application en \gls{xml} ;
\item Un système de conversion et redimensionnement d'image: lorsque l'on met une image
dans un article, elle va être redimensionnée entre autre en fonction du modèle ;
\item Un moteur de recherche.
\end{itemize}


A toutes ces fonctionnalités il faut rajouter des points plus techniques:
\begin{itemize}
\item Une couche d'abstraction de la base de données: on peut choisir entre les grands
standard du marché, MySQL, PostgreSQL, Microsoft SQL Server, ou encore Oracle ;
\item Gestion du cache, pour décharger considérablement le serveur ;
\item Gestion du "clustering", lorsqu'un seul serveur ne suffit plus.
\end{itemize}

\subsection{WebService XML}
Pour que l'application LyonCapitale puisse prendre les informations du site LyonCapitale.fr,
il a fallu développer un \gls{webservice} \gls{xml}. Ce \gls{webservice} est plus précisément un ensemble de
modèles dans Ez Publish pour générer des fichiers \gls{xml}.

A la différence d'autres outils comme \gls{ror} il n' y a pas de magie ici, on doit écrire
le \gls{xml} à la main. En effet avec \gls{ror}, on suit l'architecture REST, et on peut donc avoir
les données en \gls{xml} en ajoutant très peu de lignes dans notre application.

Ce \gls{webservice} n'a pas été défini une bonne fois pour toutes et comme le site web évolue
au fil des exigences/besoins des journalistes de LyonCapitale, le webservice présente quelques
défauts. Le webmaster du site,
Pierre Dechanoz, travaille dans le même service que moi, il a donc été très facile de faire une
copie du \gls{webservice} pour corriger les problèmes suivantes:
\begin{itemize}
\item Sur-spécialisation de certaines parties: par exemple les brèves n'étaient pas considérées
comme des articles, alors qu'elles ont tout d'un article, et sont simplement plus courtes ;
\item Mauvais "content-type": pour certains modèles le "content-type" renvoyé était "text/html"
au lieu de "text/xml", provoquant des problèmes lors de certains appels ;
\item Mauvais nettoyage/encodage du contenu: certains caractères sont interdits ou ont du sens
en \gls{xml}, et il faut donc les écrire d'une autre manière. Certains champs comme le nom de la
rubrique n'était pas nettoyé et faisait donc "exploser" l'analyseur de Titanium, qui est
très strict ;
\item Absence de certains modèles: comme rien n'est automatique, certains modèles non utilisés
ou correspondant à de nouvelles classes n'étaient pas écrits ;
\item Simplification de la navigation: chaque page renvoyée contient des items avec une
classe ("lyoncapphotarticle", "lyoncapdossier", ...), on a en plus rajouté le format
("line", "liste", "full") pour rendre la navigation totalement sans état.
\end{itemize}

Le format RSS/Atom, plus standardisé, n'a pas été retenu à la base pour faire le \gls{webservice}
car il n'inclut pas cette logique de navigation présente dans l'application.

\section{Bonnes pratiques Titanium}
Comme expliqué plus tôt, Titanium évolue très vite et tout au long de mon stage d'importants
point ont changés, y compris les bonnes pratiques. Voici donc les dernières bonnes pratiques
d'Appcelerator Titanium, bonnes pratiques qui peuvent s'appliquer dans certains cas au
développement Web.

\begin{itemize}
\item Ne pas polluer l'objet global ;
\item Utiliser un seul contexte \gls{javascript} ;
\item Utiliser l'approche CommonJS ;
\item Charger le code au plus tard ;
\item Aider à la gestion de la mémoire.
\end{itemize}

Voici les bonnes pratiques de bases de Titanium, qui permettent d'éviter les critiques
récurrentes du \gls{framework} (dans le passé en tout cas): fuites mémoires, lenteurs, ...

\subsection{Ne pas polluer l'objet global}
En \gls{javascript}, toute variable déclarée dans la portée globale ou sans le mot clé var
sont globales, ie propriété de l'objet global. Cela permet en théorie d'avoir des
variables accessibles depuis toute l'application mais c'est surtout un risque de collision
avec des librairies que l'on charge avec Ti.include.

Ti.include va exécuter le code inclus dans le contexte d'exécution
courant, ainsi on a bien accès aux variables globales, mais pas aux locales.

Pendant un temps il était conseillé de crée une variable globale unique, par exemple
"var lyoncap = \{\};", et de tout mettre dedans par la suite (lyoncap.ui, lyoncap.data, ...).
Pour ne pas polluer l'espace global, dans chaque fichier inclue via Ti.include on encapsule
le code dans une fonction auto invoqué (voir figure \ref{selfcallingfunction}).

\begin{figure}[!h]
\begin{verbatim}
(function() {
  var privateData = 'je suis caché';
})();
alert(privateData); //non definie
\end{verbatim}
	\caption{Exemple de fonction auto invoqué}
	\label{selfcallingfunction}
\end{figure}

Il est maintenant très fortement conseillé d'utiliser l'approche CommonJS.


\subsection{Utiliser un seul contexte JavaScript}
Avec Titanium il est possible d'ouvrir une nouvelle fenêtre en mettant dans le propriété url
du constructeur l'adresse d'un fichier \gls{js}. Cela a pour conséquence de lancé ce fichier
dans un nouveau contexte d'exécution, un peu comme une nouvelle application. Cela pose des
problèmes de communications entre les contextes d'exécutions, qui disposent uniquement
des événements globaux pour se parler. Cela peut aussi poser des problèmes de références
circulaires et de fuites de mémoires. Il existent très peux de cas ou on a vraiment besoin
d'un second environnement d'exécution et on ne devrait normalement pas utilisé cette approche.

\subsection{Utiliser l'approche modulaire CommonJS}
L'idée de CommonJS est de faire des modules indépendants avec une interface publique bien
définie exposé via l'objet "exports". Les modules CommonJS sont chargées une seul fois et
conservent leurs états, ie on peut très facilement implémenter une variable globale via
CommonJS. Ils sont exécutes dans un bac à sable, donc il ne pollue pas l'objet global
et toutes les variables se retrouves donc privées. Les modules CommonJS peuvent très
facilement être réutilisé, le seul point à connaitre est l'interface publique.

\begin{figure}[!h]
\begin{verbatim}
// example de module CommonJS: lib/tests.js
var private = 'donnée privée';
var compteur = 0;
exports.add = function() {
  var result = 0;
  for (var i = 0, l = arguments.length;i<l;i++) {
    result = result+arguments[i];
  }
  return result;
};
exports.inc = function(){ compteur++; };
exports.val = function(){ return compteur; };

// appel du module tests
var tests = require('lib/tests');
var sum = tests.add(2,2,2,2,2);		// sum = 10

var val = tests.val();	// val = 0
tests.inc();
val = tests.val();		// val = 1
\end{verbatim}
	\caption{Example CommonJS}
	\label{commonjs}
\end{figure}

\subsection{Charger le code au plus tard}
A chaque fois que l'on fait un "require" ou un "Ti.include" le code du fichier est chargé puis
exécuté immédiatement. Avec l'approche CommonJS (require) le fichier sera chargé une seule
fois, il est donc conseillé de faire appel au module requis le plus tard possible, par exemple
dans les écouteurs d'événements ("Event Listener"). Cela permet de réduire le temps de
démarrage de l'application.

\subsection{Aider à la gestion de la mémoire}
En \gls{javascript} la mémoire est gérée avec un ramasse miettes ("Garbage collector"), il faut
donc bien penser lorsque par exemple on supprime une vue d'une fenêtre, à supprimer toute
autre référence à la vue ( "myView = null;").

On peut aussi explicitement fermer les fenêtres de l'application, ainsi Titanium s'occupe
de nettoyer toutes les ressources associé.

Il faut faire très attention au références contenues par exemple dans les écouteurs d'événements
globaux, en effet ceux-ci ne sont détruits qu'à la fermeture de l'application donc tous les
objets référencés à l'intérieur de ceux-ci seront aussi détruits uniquement à la fermeture.


Ainsi en appliquant quelques règles simples on peut pleinement tirer partie de Titanium.


\section{Architecture et fonctionnement}
En ce qui concerne l'architecture de cette application, je l'ai découpé en deux parties,
les données (dossier "model") et la partie graphique (dossier "ui"). On a de plus un dossier
"config", contenant des paramètres comme l'adresse du \gls{webservice}, l'adresse de la publicité,
et un dossier "lib" contenant des librairies génériques.

Cette architecture n'est pas figée et va surement se rapprocher d'un modèle \gls{mvc} avec
l'ajout de l'application iPad/tablette \gls{android}, en effet les parties vues et contrôleurs
sont pour l'instant liés car il n'y a qu'un type de vue.

En ce qui concerne le fonctionnement l'application est entièrement piloté pas les événements,
et est sans état.

Chaque fichier \gls{javascript} du projet est un module CommonJS, comme recommandé par les
bonnes pratiques Titanium.

\subsection{Modules}
\subsubsection{dossier "config"}
Il contient seulement le module config.js, avec l'adresse des différents onglets de base,
la configuration du cache, l'adresse de la publicité, la clef de l'\gls{api} Facebook ...

\subsubsection{dossier "lib"}
Le dossier lib contient des librairies génériques provenant en général d'internet, qui ont
été très peu modifiés, et peuvent être réutilisées dans d'autres projets très facilement.

Il y a cachedImageView.js, librairie qui télécharge, redimensionne puis met en cache les
images distantes. Je lui ai rajouté la fonction de mettre en cache l'image redimensionnée et non pas
l'original, pour économiser du temps cpu, assez limité sur nos chers smartphones,
et aussi la fonction pour expirer le cache, ie supprimer les images de plus de X jours.

Il y a aussi cacheSQLite.js, un pilier de l'application LyonCapitale. Avec cette librairie
on va mettre en cache chaque appel au \gls{webservice}, pour améliorer les performances de
l'application. Pour pouvoir les stocker dans la base SQLite, on va sérialiser
les objets \gls{javascript} en JSON.

Pour finir on a date.format.js, pour convertir les dates \gls{javascript} en dates "françaises",
et htmlEncoder.js pour convertir du texte encodé en \gls{html} en texte normal (par exemple en
\gls{html} les guillemets '"' s'écrivent '\&quot;').


\subsubsection{dossier "model"}
Le dossier "model" contient 2 modules CommonJS: network.js et data.js.

Le module network.js s'occupe exclusivement des appels au \gls{webservice} LyonCapitale, il va
faire les requêtes, gérer les erreurs réseaux/de connexions, et enfin analyser la réponse
\gls{xml} du serveur pour en faire un objet \gls{javascript}. Ce module est principalement utilisé
à travers data.js, pour gérer le cache.

Le deuxième module, data.js, fait le lien entre network.js et la librairie cacheSQLite.js.
Il a seulement 2 fonctions publiques. La première, getData, permet de lancer la récupération
de l'objet \gls{javascript} correspondant à l'adresse passé en paramètre. Si la donnée est dans
le cache, elle envoie un événement "data:dataAvailable", dans tous les cas elle lance le
téléchargement, qui lancera les événements "data:dataUpdated" ou "data:dataNotUpdated"
suivant le cas, pour savoir s'il faut rafraîchir l'affichage.

\subsubsection{dossier "ui"}
C'est le plus gros dossier, avec la partie vue et contrôleur pour l'instant mélangés.
On y retrouve des petits modules pour certaines fonctionnalités bien spécifiques, par exemple
share.js s'occupe du partage des articles (Mail, Facebook, Twitter), brevesView.js s'occupe
d'afficher les brèves et de les faire défiler, contactWindow.js s'occupe d'afficher
les contacts et les mentions légales, ou encore activityIndicator.js s'occupe de l'affichage
du petit témoin d'activité.

Le module ui.js est le chef d'orchestre de l'application, c'est dans ce module que sont
définis tous les écouteurs d'événement globaux, et ainsi toutes les actions passent par
lui.

On retrouve aussi applicationWindow.js, qui s'occupe de la création des fenêtres, et de
l'harmonisation de leur comportement entre les deux plateformes.

On peut encore citer tableView.js, qui s'occupe de l'affichage des listes d'articles,
et fullView.js, qui s'occupe de l'affichage des articles en entier.


\subsection{Fonctionnement}
Comme dit plus haut l'application est sans état et est entièrement pilotée par les événements.
L'idée est que lors de la création d'une fenêtre, on va attacher à cette fenêtre certaines
propriétés pour renseigner le contenu que doit avoir la fenêtre, on a donc pas besoin de
savoir d'où on vient (fenêtre précédente ou autres) ce qui simplifie grandement le code.

Dans la plupart des cas ce sera la propriété "lcUrl"
(lc pour LyonCapitale) qui va contenir l'adresse du contenu
à afficher. Lorsque l'on va afficher la fenêtre elle va déclencher l'événement "focus",
à ce moment-là on va envoyer un événement global, "win:currentWindowFocus",
qui va être reçu et traité par des fonctions de ui.js, qui vont par exemple lancer
le téléchargement des données depuis le \gls{webservice} via "data.getData(lcUrl)".
Si les données sont immédiatement disponibles on aura un événement "data:dataAvailable",
puis en fonction des données téléchargées on aura l'événement "data:dataUpdated" ou
"data:dataNotUpdated". Si la page n'a jamais été affichée, "data:dataAvailable" déclenche
cet affichage, sinon on rafraîchit l'affichage uniquement sur l'événement "data:dataUpdated".


Pour boucler la boucle, lorsque l'on clique sur un article pour l'ouvrir, on envoie un
événement "win:openLcUrl" avec l'url en question, cette événement va être capté dans
ui.js, qui va appeler applicationWindow.js pour créer la nouvelle fenêtre avec la
propriété "lcUrl", qui quand elle va s'afficher va déclencher l'événement "focus" ...
 
L'explication précédente est intentionnellement simplifiée, mais l'idée est bien d'envoyer
des événements globaux de n'importe quel endroit dans le code, dès que nécessaire,
et d'écouter tous les événements globaux dans ui.js. Cette centralisation permet plus de
flexibilité, on peut changer un traitement sans chercher dans le code où est appelé ce
traitement. Par exemple pour l'instant les deux événements "data:dataAvailable" et
"data:dataUpdated" renvoient vers la même fonction.




\section{Limitations et bugs}
Même si lors de mon stage Titanium a subit de grandes amélioration, autant sur le côté
logiciel (\gls{sdk} et \gls{ide}) que du côté documentation et guides, des problèmes subsistent.

\subsection{Performances}
L'application LyonCapitale est un lecteur de journal destiné au grand publique,
de ce fait les utilisateurs ne comprennent pas pourquoi une application saccade quand
d'autres applications similaires comme "LeMonde", "20Minutes", "Libération" marchent très bien.

Les performances mêmes si elles se sont grandement améliorées, posent encore problème avec
\gls{android} dans certains cas. Le \gls{framework} a dans un premier temps changé de moteur \gls{javascript}
pour \gls{android}, en passant de Rhino à V8 lors de la version 1.8, ce qui a permis de faire
exploser la vitesse de traitement \gls{javascript}. Mais d'autres problèmes subsistent.

Les "tableViews" sont des sortes de tableaux défilants. On ajoute des lignes personnalisées
(dans notre cas une image et 3 textes) et en théorie le \gls{framework} nous affiche ça à la
vitesse de la lumière car il y a des optimisations pour ne charger que les lignes visibles.
Ces fameuses "tableViews" ont été en partie améliorées entre la version 1.8 et la 2.0 du \gls{sdk},
ce qui a fait passer l'expérience utilisateur de médiocre à moyenne, car de petites saccades
persistent.

Comme je vais en avoir besoin pour l'application iPad/tablette \gls{android}, je me suis
intéressé aux "ScrollViews", qui sont simplement des vues défilantes, ont y met une vue
trop grande pour l'écran et on peu défiler haut-bas, gauche-droite ou les deux. Les
"ScrollViews" sont plus génériques que les "tableViews", et n'intègre aucune optimisation.
J'ai quand même par curiosité remplacé les "tableViews" par des "scrollViews" et là, surprise,
les performances sont excellentes, défilement parfaitement fluide. Il a simplement fallu
réécrire certains effets graphiques intégrés dans les "tableViews" et non dans les
"scrollViews" et nous voilà avec une application fluide avec \gls{android}.

L'application est fluide même avec un HTC Tattoo mise à jour en
\gls{android} 2.3, un des téléphones les moins puissants supportant \gls{android} 2.3
(500 MHz, 256Mo ram).

Ainsi l'utilisation de l'outil générique au lieu du sur mesure donne parfois une plus
grande satisfaction, à suivre dans les prochaines versions.

\subsection{Débogage}
Un bon débogueur peut faire gagner un temps précieux lors de la mise au point d'un
logiciel. On a ici deux principales limitations, des petits bugs dans le débogueur et
de gros problèmes avec l'émulateur \gls{android}.

En ce qui concerne le débogueur, il n'affiche pas toujours bien les objets \gls{javascript}s. Si
un objet a trop de propriétés, soit le débogueur va en oublier une partie, soit il va
planter lorsque l'on veux en afficher une. Cela reste une aide appréciable mais il faut en
aucun cas s'y fier à 100\%.

Pour la partie \gls{android}, les problèmes viennent de l'émulateur \gls{android} qui est d'une
qualité proche de 0. En effet le lancement de ce dernier prend une éternité, puis en
général l'application ne se lance pas, alors qu'elle fonctionne parfaitement sur les
périphériques de tests. On peut déjà débogueur une bonne partie de notre application
avec le simulateur \gls{ios}, d'une bien meilleure qualité lui, mais lorsque l'on rencontre des
problèmes spécifiques \gls{android}, on est un peu dans le noir. Sur \gls{android} il est
techniquement possible de débogueur sur le téléphone, mais cela n'as pas été implémenté
dans Titanium. Il nous reste uniquement l'écriture de message de debug sur la console,
console à laquelle on a accès via usb et l'utilitaire adb.

\subsection{IDE}
L'\gls{ide} s'améliore petit à petit, mais il garde pour l'instant deux grands défauts.

Le premier est la nécessité d'avoir une connexion internet lorsqu'on le démarre, ce qui
permet à Appcelerator de collecter des statistiques, et surement aussi de gérer les
extensions (plugins) payantes, mais nous met au chômage technique en cas de coupure internet.

Le deuxième défaut est l'autocomplétion qui marche assez mal, elle arrête parfois de
s'afficher et elle propose seulement les fonctions de l'\gls{api} Titanium, pas les fonctions
ou variables de notre code.


\subsection{Divers}
La liste des problèmes est longue, et très souvent c'est un problème de parité entre
\gls{ios} et \gls{android}. Sur \gls{ios}, les vidéos \gls{html}5 dans une webview marchent
parfaitement, alors que sur \gls{android} non. De même pour l'événement "swipe", marche
très bien à l'intérieur de la webview pour \gls{ios},et à l'extérieur (sur l'objet webview)
pour \gls{android}. Pour les fenêtres, lorsque l'on ferme une fenêtre qui en recouvre une
autre, sous \gls{ios} l'événement "focus" est lancé, alors que \gls{android} considère que
la fenêtre ayant été déjà affiché par le passé, il ne doit pas lancé un événement "focus".


\section{Tests}
Pour les tests, il n'y a eu aucune automatisation. En effet il n'existe pas encore à ce
jour de librairie de tests intégrée dans Titanium. De plus les problèmes venant de la
multitude de versions \gls{android}, ou des différences avec \gls{ios} ne sont pas du tout
triviaux. L'automatisation n'étant pas possible, j'ai développé de manière incrémentale, je
suis parti d'une application minimaliste et à chaque fois j'ai ajouté une fonctionnalité
puis je l'ai testé sur tous les périphériques disponibles (liste page \pageref{listemobile}).

Une fois l'application mature, nous avons commencé une phase de beta tests avec les
journalistes de LyonCapitale. Après un premier test complet qui a permis de faire remonter
plein de détails fonctionnels, à chaque nouvelle version j'ai joint la liste des changements,
pour qu'ils puissent valider les nouveautés.

\section{Résultats}

A l'heure actuelle j'ai porté l'application iPhone sous Titanium, et à partir d'une base
de code on a donc ces deux versions de l'application, une \gls{ios} et une \gls{android}.
Toutes les fonctionalités de l'ancienne application ont été integrés. Avant de publier les
nouvelles applications sur l'\gls{appstore} et le \gls{googleplay}, nous intégrons
de nouvelles fonctionnalités, comme le "push", l'"in app purchase", le défilement sans fin
(lorsque l'on arrive en bas d'une liste la page suivante se charge à la suite), le "swipe"
(lorsque l'on fait un mouvement vers la gauche ou la droite on charge l'article suivant ou
précédant), ou encore une meilleure gestion du cache.

Comme on peut l'observer sur les copies d'écrans de la figure \ref{lyoncapnew}, Titanium
nous mâche une partie du travail sans céder sur les conventions graphiques des plateformes
(emplacement des onglets, couleurs, ...).

\begin{figure}[!h]
\begin{center}
    \includegraphics[height=0.4\textheight]{lyoncapnew.png}
        ~
    \includegraphics[height=0.4\textheight]{lyoncapnewandroid.jpg}
	\caption{Nouvelles applications LyonCapitale (versions \gls{ios} et \gls{android})}
	\label{lyoncapnew}
\end{center}
\end{figure}